## @package karboom.states
# Extended states
#
# Extensions of the karboom.classes.State
#

from __future__ import division

from karboom.classes import State

## Static state
#
# Changes the state of the layer to elements without animation
#
class StaticState(State):
    
    def __render__(self):
        State.__render__(self)
        
        for e in sorted(self.elements, key = lambda x: x.precedence):
            e.context, e.layer, e.fps, e.size, e.frame, e.state = self.context, self.layer, self.fps, self.size, self.frame, self
            e.__render__()
            del e.context, e.layer, e.fps, e.size, e.frame, e.state

## Animated state
#
# Animates a state change
#
class AnimatedState(State):
    
    ## Start time of state
    starttime = 0.0
    
    ## End time of state
    endtime = 0.0
    
    ## Animation acceleration scalar
    accel = 1.0
    
    def __render__(self):
        State.__render__(self)
        
        if self.frame >= self.endtime * self.fps:
            for e in sorted(self.elements, key = lambda x: x.precedence):
                e.context, e.layer, e.fps, e.size, e.frame, e.state = self.context, self.layer, self.fps, self.size, self.frame, self
                e.__render__()
                del e.context, e.layer, e.fps, e.size, e.frame, e.state
        
        else:
            
            # Build a better pairing algorithm!
            elementsa = sorted(self.layer.states[self.layer.states.index(self) - 1].elements, key = lambda x: x.precedence) # Order elements in the previous state by precedence
            elementsb = sorted(self.elements, key = lambda x: x.precedence) # Order elements in the current state by precedence
            
            classnames = [] # Empty class names list for appending
            
            map(lambda x: classnames.append(x.__class__.__name__) if not x.__class__.__name__ in classnames else None, elementsa) # Get a list of all the element classes in the previous state 
            map(lambda x: classnames.append(x.__class__.__name__) if not x.__class__.__name__ in classnames else None, elementsb) # Get a list of all the element classes in the current state
            
            pairedelements = [] # List of paired elements, in 2-tuples
            
            for c in classnames:
                i = 0 # Initialise index counter
                
                flista = filter(lambda x: x.__class__.__name__ == c, elementsa) # Get all elements in the previous state whose classes are c
                flistb = filter(lambda x: x.__class__.__name__ == c, elementsb) # Get all elements in the current state whose classes are c
                
                for o in flista:
                    try:
                        pairedelements.append((o, flistb[i])) # Assume that the size of both lists are the same 
                    except IndexError: # Not enough elements in the current state
                        self.elements.append(o) # Reference the element from the last state
                        pairedelements.append((o, o)) # Pair element against itself
                    i += 1 # Increase index
                
                for o in flistb[i:]: # Pair the remaining elements in the current state
                    pairedelements.append((o.__class__(), o)) # Pair it against a blank element of the same class
            
            # End of inefficient pairing algorithm
            
            for el in pairedelements:
                el[0].context, el[0].layer, el[0].fps, el[0].size, el[0].frame = self.context, self.layer, self.fps, self.size, self.frame
                el[1].context, el[1].layer, el[1].fps, el[1].size, el[1].frame = self.context, self.layer, self.fps, self.size, self.frame
                
                if el[0] is el[1]:
                    elfin = el[0]
                else:
                    elfin = el[0].__class__.__interpolate__((self.frame - self.starttime * self.fps)/((self.endtime - self.starttime) * self.fps), el[0], el[1], self.accel)
                
                elfin.context, elfin.layer, elfin.fps, elfin.size, elfin.frame, elfin.state = self.context, self.layer, self.fps, self.size, self.frame, self
                elfin.__render__()
                del elfin.context, elfin.layer, elfin.fps, elfin.size, elfin.frame, elfin.state